import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//import Assignment2.keyListener;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClient;
import com.amazonaws.services.cloudwatch.model.Datapoint;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsRequest;
import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsResult;
import com.amazonaws.services.ec2.model.DeregisterImageRequest;
import com.amazonaws.services.ec2.model.DetachVolumeRequest;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;


public class Monitor implements Runnable{

	 private String instanceId; 
	 private AmazonCloudWatchClient cloudWatchClient; 
	 private boolean c = true;
	 private Hub hub;
	 private AWSCredentials credentials;
	 private User user;
	 
	 public void run()
	 {
		    
		 for (;;) 
		 {     
			 ArrayList<HashMap<String,Double>> measureSet = retrieveMeasureSet();       
			 try {
				if(!(measureSet.size()<=0))
			    {
				   if(measureSet.get(0).get("averageCPU")<17)
				   {   
					   System.out.println("cpu usage below 17% for user: "+credentials.getAWSAccessKeyId());
					   synchronized(this){
					   DetachVolumeRequest dvr = new DetachVolumeRequest();
			           dvr.setVolumeId(this.user.getVolumnId());
			           dvr.setInstanceId(instanceId);
			           
			           hub.ec2.detachVolume(dvr);
			           User u=User.getUser(credentials);
			           if(u != null){
			        	   DeregisterImageRequest dir = new DeregisterImageRequest(u.getAMIid()); 
			        	   hub.ec2.deregisterImage(dir);
			           }
			           Thread.sleep(30000);
			            
			           
					   ImageCreater ci = new ImageCreater(instanceId,credentials);
	                   String imageId = ci.setImage(instanceId, "Img1", hub.ec2);
	                  
	                   if(u!=null)
	                   {
	                	   u.update("AMIid", imageId);
	                	   u.update("volumnId", this.user.getVolumnId());
	                   }
	                   else
	                	   {
	                	    this.user.setAMIid(imageId);
	                	    this.user.persist();
	                	   }
	                   System.out.println("waiting for image named "+ ci.getImageName()+"with ImageId: "+ imageId + " being stored for user: "+credentials.getAWSAccessKeyId());
//	                   Image image1 = new Image();
//	                   image1.setImageId(imageId);
//	                   System.out.print(image1.getState());
			           }
	                   Thread.sleep(300000);

//	                   System.out.print(image1.getState());
	             
					   System.out.println("shutdown for user: "+credentials.getAWSAccessKeyId());
					   ArrayList<String> arr=new ArrayList<String>();
					   arr.add(instanceId);
					   TerminateInstancesRequest tir = new TerminateInstancesRequest(arr);
					   hub.ec2.terminateInstances(tir);
			                   
				       ExecutorService exec=Executors.newCachedThreadPool();
				       Hub.keyListener listener=this.hub.new keyListener();
				       listener.setVisible(true);

				       exec.execute(listener);

				       exec.shutdown();
				       break;
				   }
			    }
				Thread.sleep(60000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}  
		} 
	 }
	 
	 public Monitor(String instanceId,Hub a, User u) 
	 {   
		 cloudWatchClient = new AmazonCloudWatchClient(u.getCredentials());   
		 this.instanceId = instanceId; 
		 this.hub=a;
		 this.credentials=u.getCredentials();
		 this.user=u;
	 }
	 
	 public ArrayList<HashMap<String,Double>> retrieveMeasureSet() 
	 {   
		 ArrayList<HashMap<String,Double>> rs= new ArrayList<HashMap<String,Double>>();
		 GetMetricStatisticsRequest statRequest = new GetMetricStatisticsRequest();
			
			//set up request message
			statRequest.setNamespace("AWS/EC2"); //namespace
			statRequest.setPeriod(60); //period of data
			ArrayList<String> stats = new ArrayList<String>();
			
			//Use one of these strings: Average, Maximum, Minimum, SampleCount, Sum 
			stats.add("Average"); 
			stats.add("Sum");
			statRequest.setStatistics(stats);
			
			//Use one of these strings: CPUUtilization, NetworkIn, NetworkOut, DiskReadBytes, DiskWriteBytes, DiskReadOperations  
			statRequest.setMetricName("CPUUtilization"); 
			
			// set time
			GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
			calendar.add(GregorianCalendar.SECOND, -1 * calendar.get(GregorianCalendar.SECOND)); // 1 second ago
			Date endTime = calendar.getTime();
			calendar.add(GregorianCalendar.MINUTE, -10); // 10 minutes ago
			Date startTime = calendar.getTime();
			statRequest.setStartTime(startTime);
			statRequest.setEndTime(endTime);
			
			//specify an instance
			ArrayList<Dimension> dimensions = new ArrayList<Dimension>();
			dimensions.add(new Dimension().withName("InstanceId").withValue(instanceId));
			statRequest.setDimensions(dimensions);
			
			//get statistics
			GetMetricStatisticsResult statResult = cloudWatchClient.getMetricStatistics(statRequest);
			
			//display
			//System.out.println(statResult.toString());
			List<Datapoint> dataList = statResult.getDatapoints();
			Double averageCPU = null;
			Date timeStamp = null;
			for (Datapoint data : dataList){
				HashMap<String,Double> hm = new HashMap<String,Double>();
				averageCPU = data.getAverage();
				timeStamp = data.getTimestamp();
				System.out.println("Average CPU utlilization for last 10 minutes: "+averageCPU + "% for user: "+credentials.getAWSAccessKeyId());
				System.out.println("Totl CPU utlilization for last 10 minutes: "+data.getSum() + "% for user: "+credentials.getAWSAccessKeyId());
				hm.put("averageCPU", averageCPU);
				hm.put("sumCPU", data.getSum());
				rs.add(hm);
			}
			return rs;
	 }
	 
	 public boolean returnstop(){
		 return c;
	 }	 
}
